#include "riscv-it.h"
#include "riscv-plic.h"
#include "riscv-csr.h"
#include "scu.h"
#include "uart.h"
#include "reg_common.h"

volatile int8_t byte_read;

/* Machine Software Interrupt ID #3 */
void software_handler (void) {
    /* Add functionality if desired */
    printf("Interrupt: %s", __FUNCTION__);

}

/* Machine Timer Interrupt ID #7 */
void timer_handler (void) {
    /* Add functionality if desired */
    // printf("Interrupt: %s", __FUNCTION__);
    // TIMER_REG =     0x0000000000000000;
    // TIMER_CMP_REG = 0x0000000000000000;
    // timer_inter_flag = 1;
}

/* External Interrupt ID #11 - handles all global interrupts from PLIC */
void external_handler (void) {
    /* Add functionality if desired */
    DBG_LSB_REG = 0x0;
    DBG_MSB_REG = 0x0;
    uint32_t id = ID_0_REG; // claim
    if(id == 5)
        byte_read = read32(UART_BASE_ADDR); 
        //byte_read = UART2->RBR; 
    ID_0_REG = id; // Complite
    printf("Interrupt: %i\r\n", id);
}

/* PLIC Interrupt`s ID #27 - 80 */
void default_vector_handler (void) {
    /* Add functionality if desired */
    printf("Interrupt: %s", __FUNCTION__);

}

void __attribute__((weak, interrupt ("machine"))) wdt_vector_handler (void){
    /* Add functionality if desired */

}

void __attribute__((weak, interrupt ("machine"))) gp_timer_vector_handler (void){
    /* Add functionality if desired */

}

void __attribute__((weak, interrupt ("machine"))) boot_spi_vector_handler (void){
    /* Add functionality if desired */

}

void __attribute__((weak, interrupt ("machine"))) gp_spi_vector_handler (void){
    /* Add functionality if desired */

}

void __attribute__((weak, interrupt ("machine"))) mailbox_vector_handler (void){
    /* Add functionality if desired */


}

void __attribute__((weak, interrupt ("machine"))) uart_vector_handler (void){
    /* Add functionality if desired */
    printf("Interrupt: %s", __FUNCTION__);

}
void __attribute__((weak, interrupt ("machine"))) i2c_vector_handler (void){
    /* Add functionality if desired */


}
void __attribute__((weak, interrupt ("machine"))) gbe0_vector_handler (void){
    /* Add functionality if desired */


}
void __attribute__((weak, interrupt ("machine"))) gbe1_vector_handler (void){
    /* Add functionality if desired */

}
void __attribute__((weak, interrupt ("machine"))) usb0_vector_handler (void){
    /* Add functionality if desired */

}
void __attribute__((weak, interrupt ("machine"))) usb1_vector_handler (void){
    /* Add functionality if desired */


}

/* Exception handler */
void default_exception_handler(void) {
    /* Add functionality if desired */
    uint64_t mcause = csr_read_mcause();
    
    printf("Exception: %i", mcause);
    return 0;
}

void set_interrupt_mode(uint8_t mode)
{
    uint64_t mtvec_base;

    /* Write mstatus.mie[3] = 0 to disable all machine interrupts prior to setup */
    csr_clr_bits_mstatus(MSTATUS_MIE_BIT_MASK);

    /* Setup mtvec to point to our exception handler table using mtvec.base[mxlen-1:2] and assign mtvec.mode[1:0] = 1 */
    mtvec_base = (uint64_t)&__mtvec_clint_vector_table;
    csr_write_mtvec(mtvec_base | mode);

    /* Write mstatus.mie = 1 to enable all machine interrupts */
    csr_set_bits_mstatus(MSTATUS_MIE_BIT_MASK);
}

void enable_interrupt(uint8_t interrupt_src, uint8_t interrupt_dest)
{
    volatile uint32_t * ptr = &(SCU->IRQ_MASK_MAP_CONTROL_0) + interrupt_src;
    *ptr = (interrupt_dest << 16U) | 1U;
}

void disable_interrupt(uint8_t interrupt_src, uint8_t interrupt_dest)
{
    volatile uint32_t * ptr = &(SCU->IRQ_MASK_MAP_CONTROL_0) + interrupt_src;
    *ptr = (interrupt_dest << 16U) | 0U;
}
